using System;
using System.Collections.Generic;
using System.Drawing;
//using OhioState.FileService;
using System.IO;
using System.Windows.Forms;
using OhioState.AssetManaged;
using OhioState.Graphics.Proxy;


namespace OhioState.Controls.GLSL
{
    public partial class GLSLEditorCtrl : UserControl
    {
        //
        // Pointer to the instance of the asset manager
        //
        private AssetManager assetMan;

        //
        // List of templates
        //
        private List<ShaderRoutine> templates;

        //
        // GLSL Editor type: Vertex Shader editor or Fragment Shader Editor 
        //
        private Type editType;

        //
        // Instance of ShaderRoutine that is currently selected 
        //
        private ShaderRoutine shaderRoutine;
        
        //
        // Compile delegate and compile event.  This is used to dispatch a message that the compile
        //  button has been clicked.  At creation time the proper linkage should be done to set this up.
        //  This no only allows this control to decouple from an OpenGL functionality, but also allows
        //  remote clients to call compile and have the compile event occur on the server instead of the client.
        //
        public delegate bool CompileHandler(ShaderRoutine shaderRoutine);
        public CompileHandler CompileEvent;

        //
        // Default Shaders
        //
        public static String defaultVertShader = String.Empty;
        public static String defaultFragShader = String.Empty;

        public GLSLEditorCtrl()
        {
            InitializeComponent();

            //
            // Get a pointer to the instance of the asset manager and create templates list
            //
            assetMan = AssetManager.Instance;
            templates = new List<ShaderRoutine>();

            //
            // Set up event handler for selection changed event
            //
            shaderRoutineAssetManCtrl.SelectedEvent += new IAssetManagedListHandler(assetManagerControl_SelectedEvent);
        }

        //
        // Initialization can be done only if an instance of GLSLEditorHelper has been created 
        //
        public void Init(Type type)
        {
            // 
            // Initialize type (vertex/fragment)
            //
            editType = type;

            //
            // Initialize the control and shader depending on the type
            //
            if (type == typeof(VertexShader))
            {
                //shaderRoutineAssetManCtrl.Init(typeof(VertexShader));

                List<Type> types = new List<Type>();
                types.Add(typeof(VertexShader));
                shaderRoutineAssetManCtrl.Init(types);

                shaderRoutine = new VertexShader("Untitled");
            }
            else
            {
                //shaderRoutineAssetManCtrl.Init(typeof(FragmentShader));
                List<Type> types = new List<Type>();
                types.Add(typeof(FragmentShader));
                shaderRoutineAssetManCtrl.Init(types);

                shaderRoutine = new FragmentShader("Untitled");
            }
            //
            // Create default shader routines
            //
            SetupDefaultShaderRoutines();

            //
            // Set up the drop down for the templates
            //
            BuiltTemplateDropDown();
        }

        #region Setup Default Shader Routines
        //
        // Create a default shader routine and load it into the asset manager
        //
        private void SetupDefaultShaderRoutines()
        {
            if (editType == typeof(VertexShader))
            {
                VertexShader vertex = new VertexShader("defaultVertexShader", defaultVertShader);
                templates.Add(vertex);
            }
            else
            {
                FragmentShader fragment = new FragmentShader("defaultFragmentShader", defaultFragShader);
                templates.Add(fragment);
            }
        }
        #endregion

        //
        // Setup the drop down list of all templates
        // Clear the Drop down menu and then add each item from the template list to the
        // drop down menu.  Create preview icons as well.
        //
        private void BuiltTemplateDropDown()
        {
            newToolStripButton.DropDownItems.Clear();
            Image image = new Bitmap(32, 32); // global::GLSLControl.Properties.Resources.Text_icon;
            foreach (ShaderRoutine obj in templates)
            {
                newToolStripButton.DropDownItems.Add(obj.Name, image, CreateNewFromTemplate);
            }
        }

        //
        // Gets a shader routine from the template list given its name
        //  or returns null if it doesn't exist.
        //
        private ShaderRoutine GetTemplate(String name)
        {
            foreach (ShaderRoutine shader in templates)
            {
                if (shader.Name == name)
                {
                    return shader;
                }
            }
            return null;
        }

        //
        // Event handler for Template Drop down clicks
        //  Find the shader routine that corresponds to the drop down item,
        //  clone it and add it to the asset manager.
        //
        public void CreateNewFromTemplate(Object sender, EventArgs e)
        {
            if (sender.GetType() == typeof(ToolStripMenuItem))
            {
                String name = ((ToolStripMenuItem)sender).Text;
                ShaderRoutine shader = GetTemplate(name);
                if (shader != null)
                {
                    IAssetManaged obj = assetMan.Add(shader.Clone());
                }
            }
        }

        //
        // Event handler for selection changed event
        //  This changes the shader routine 
        //
        public void assetManagerControl_SelectedEvent_thisThread(ShaderRoutine shader)
        {
            shaderRoutine = shader;
            syntaxBoxControl1.Document.Clear();
            syntaxBoxControl1.Document.Text = shaderRoutine.ShaderContent;
            logInfoRichTextBox.Text = shaderRoutine.CompileInfo;
        }

        public void assetManagerControl_SelectedEvent(IList<IAssetManaged> items)
        {
            if (items.Count > 0)
            {
                try
                {
                    if (this.InvokeRequired)
                    {
                        //
                        // We need to make sure these methods are executed on the correct thread.
                        //
                        this.Invoke((MethodInvoker)delegate { assetManagerControl_SelectedEvent(items); } );
                    }
                    else
                    {
                        shaderRoutine = items[0] as ShaderRoutine;
                        syntaxBoxControl1.Document.Clear();
                        syntaxBoxControl1.Document.Text = shaderRoutine.ShaderContent;
                        logInfoRichTextBox.Text = shaderRoutine.CompileInfo;
                    }
                }
                catch { }
            }
        }

        //
        // Save button - saves the currently selected shader routine to a file.
        //
        private void saveButton_Click(object sender, EventArgs e)
        {
            if (shaderRoutineAssetManCtrl.GetSelected().Count > 0)
            {
                if (editType == typeof(VertexShader))
                {
                    saveFileDialog.Filter = "Vertex Shader Files (*.vert)|*.vert";
                }
                else
                {
                    saveFileDialog.Filter = "Fragment Shader Files (*.frag)|*.frag";
                }
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                {
                    bool isShader = false;
                    if (editType == typeof(VertexShader))
                    {
                        isShader = (Path.GetExtension(saveFileDialog.FileName)== ".vert");
                    }
                    else
                    {
                        isShader = (Path.GetExtension(saveFileDialog.FileName) == ".frag");
                       
                    }

                    System.IO.Stream stream = null;
                    if ((stream = saveFileDialog.OpenFile()) != null)
                    {
                        if (stream != null)
                            shaderRoutine.SaveToFile(saveFileDialog.FileName, syntaxBoxControl1.Document.Text, stream);
                    }
                }
            }
        }

        //
        // New button - Create a new shader routine for the user to edit
        //
        private void newButton_Click(object sender, EventArgs e)
        {
            if (shaderRoutineAssetManCtrl.GetSelected().Count > 0)
            {
                shaderRoutine = ((ShaderRoutine)shaderRoutineAssetManCtrl.GetSelected()[0]).Clone();
                shaderRoutine.SetName(shaderRoutine.Name + " Copy");
                syntaxBoxControl1.Document.Clear();
                syntaxBoxControl1.Document.Text = shaderRoutine.ShaderContent;
            }
            else
            {
                if (editType == typeof(VertexShader))
                    shaderRoutine = new VertexShader("Untitled");
                else
                    shaderRoutine = new FragmentShader("Untitled");
                shaderRoutine.ShaderContent = syntaxBoxControl1.Document.Text;
            }
            IAssetManaged obj = assetMan.Add(shaderRoutine);
        }

        //
        // Remove button - remove the currently selected shader routine from the asset
        //  manager. 
        //
        private void removeButton_Click(object sender, EventArgs e)
        {
            List<IAssetManaged> list = shaderRoutineAssetManCtrl.GetSelected();
            foreach (IAssetManaged obj in list)
            {
                assetMan.Remove(obj);
            }
        }

        //
        // Open button - calls a dialog to open a file that contains a shader routine,
        //  and adds it to the asset manager.  In both this and save the filenames in the dialogs
        //  should be populated by the asset manager if applicable.
        //
        private void openButton_Click(object sender, EventArgs e)
        {
            if (editType == typeof(VertexShader))
            {
                openFileDialog.Filter = "Vertex Shader Files (*.vert)|*.vert|All Files (*.*)|*.*";
            }
            else
            {
                openFileDialog.Filter = "Fragment Shader files (*.frag)|*.frag|All Files (*.*)|*.*";
            }
            openFileDialog.InitialDirectory = System.Windows.Forms.Application.StartupPath + "\\..\\Shaders\\VolumeRendering";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string[] files = openFileDialog.FileNames;
                foreach (string file in files)
                {
                    String name = Path.GetFileName(file);
                    if (editType == typeof(VertexShader))
                        shaderRoutine = new VertexShader(name);
                    else
                        shaderRoutine = new FragmentShader(name);
                    shaderRoutine.ShaderContent = ShaderRoutine.LoadFromFile(file);
                    IAssetManaged obj = assetMan.Add(shaderRoutine);
                    // check for duplicate
                    if (obj == shaderRoutine)
                    {
                        // add the new item to the template list and the template drop down if it doesn't
                        //  already exist
                        if (GetTemplate(shaderRoutine.Name) == null)
                        {
                            templates.Add((ShaderRoutine)obj);
                            BuiltTemplateDropDown();
                            syntaxBoxControl1.Document.Text = shaderRoutine.ShaderContent;
                            // Log information
                            logInfoRichTextBox.Focus();
                            logInfoRichTextBox.AppendText("New Routine Loaded from " + name + "\n");
                            logInfoRichTextBox.ScrollToCaret();
                        }
                    }
                }
            }
        }

        //
        // Compile Button - we can compile as many as shader routines we want.
        // It will load and compile the contents in the editor for the selected routines 
        //
        private void compileButton_Click(object sender, EventArgs e)
        {
            //logInfoRichTextBox.Clear();
            //if (shaderRoutineAssetManCtrl.GetSelected().Count == 1)
            //{
            //    // get the current content from the text box
            //    shaderRoutine.ShaderContent = syntaxBoxControl1.Document.Text;
            //    GLShader.Instance.Compile(shaderRoutine);
            //    logInfoRichTextBox.Text = shaderRoutine.CompileInfo;
            //}
            //else 
            if (shaderRoutineAssetManCtrl.GetSelected().Count > 0)
            {
                List<IAssetManaged> routines = shaderRoutineAssetManCtrl.GetSelected();
                foreach (ShaderRoutine routine in routines)
                {
                    routine.ShaderContent = syntaxBoxControl1.Document.Text;
                    //
                    // Use delegates with Invoke to call compile
                    //
                    CompileEvent.Invoke(routine);
                    //GLShader.Instance.Compile(routine);

                    // This field should be populated now
                    logInfoRichTextBox.Focus();
                    logInfoRichTextBox.AppendText(routine.CompileInfo + "\n");
                    logInfoRichTextBox.ScrollToCaret();
                }
            }
            else
            {
                logInfoRichTextBox.Focus();
                logInfoRichTextBox.AppendText("No Shader Routine Selected for Compile\n");
                logInfoRichTextBox.ScrollToCaret();
            }
        }

        private void richTextBox1_Leave(object sender, EventArgs e)
        {
            if (shaderRoutineAssetManCtrl.GetSelected().Count > 0)
            {
                shaderRoutine = (ShaderRoutine)shaderRoutineAssetManCtrl.GetSelected()[0];
                shaderRoutine.BeginManipulation();
                shaderRoutine.ShaderContent = syntaxBoxControl1.Document.Text;
                shaderRoutine.EndManipulation();
            }
        }

        private void richTextBox1_Enter(object sender, EventArgs e)
        {
            if (syntaxBoxControl1.Document.Text == "// Edit Shader Here")
            {
                syntaxBoxControl1.Document.Clear();
            }
        }

    }
}

